frontend/pages/e/[uuid]/details.tsx (view raw)
1import moment from 'moment';
2import Button from '@material-ui/core/Button';
3import Box from '@material-ui/core/Box';
4import Link from '@material-ui/core/Link';
5import Paper from '@material-ui/core/Paper';
6import Divider from '@material-ui/core/Divider';
7import Container from '@material-ui/core/Container';
8import TextField from '@material-ui/core/TextField';
9import Typography from '@material-ui/core/Typography';
10import {makeStyles} from '@material-ui/core/styles';
11import {DatePicker} from '@material-ui/pickers';
12import {PropsWithChildren, useState} from 'react';
13import {useTranslation} from 'react-i18next';
14import ShareEvent from '../../../containers/ShareEvent';
15import useEventStore from '../../../stores/useEventStore';
16import useToastStore from '../../../stores/useToastStore';
17import useSettings from '../../../hooks/useSettings';
18import EventLayout, {TabComponent} from '../../../layouts/Event';
19import {
20 EventByUuidDocument,
21 useUpdateEventMutation,
22} from '../../../generated/graphql';
23import pageUtils from '../../../lib/pageUtils';
24
25interface Props {
26 eventUUID: string;
27}
28
29const Page = (props: PropsWithChildren<Props>) => {
30 return <EventLayout {...props} Tab={DetailsTab} />;
31};
32
33const DetailsTab: TabComponent = ({}) => {
34 const {t} = useTranslation();
35 const settings = useSettings();
36 const [updateEvent] = useUpdateEventMutation();
37 const addToast = useToastStore(s => s.addToast);
38 const setEventUpdate = useEventStore(s => s.setEventUpdate);
39 const event = useEventStore(s => s.event);
40 const [isEditing, setIsEditing] = useState(false);
41 const idPrefix = isEditing ? 'EditEvent' : 'Event';
42 const classes = useStyles();
43
44 const onSave = async e => {
45 try {
46 const {uuid, ...data} = event;
47 const {id, travels, waitingPassengers, __typename, ...input} = data;
48 await updateEvent({
49 variables: {uuid, eventUpdate: input},
50 refetchQueries: ['eventByUUID'],
51 });
52 setIsEditing(false);
53 } catch (error) {
54 console.error(error);
55 addToast(t('event.errors.cant_update'));
56 }
57 };
58
59 const modifyButton = isEditing ? (
60 <Button
61 variant="contained"
62 color="primary"
63 className={classes.modify}
64 onClick={onSave}
65 >
66 {t('event.details.save')}
67 </Button>
68 ) : (
69 <Button
70 variant="text"
71 color="primary"
72 className={classes.modify}
73 onClick={() => setIsEditing(true)}
74 >
75 {t('event.details.modify')}
76 </Button>
77 );
78
79 if (!event) return null;
80
81 return (
82 <Box className={classes.root}>
83 <Container maxWidth="sm" className={classes.card}>
84 <Paper className={classes.paper}>
85 {modifyButton}
86 <div className={classes.section}>
87 <Typography variant="h6">{t('event.fields.name')}</Typography>
88 {isEditing ? (
89 <TextField
90 fullWidth
91 value={event.name}
92 onChange={e => setEventUpdate({name: e.target.value})}
93 name="name"
94 id="EditEventName"
95 />
96 ) : (
97 <Typography variant="body1" id={`${idPrefix}Name`}>
98 {event.name ?? t('event.fields.empty')}
99 </Typography>
100 )}
101 </div>
102 <div className={classes.section}>
103 <Typography variant="h6">{t('event.fields.date')}</Typography>
104 {isEditing ? (
105 <DatePicker
106 fullWidth
107 placeholder={t('event.fields.date_placeholder')}
108 value={event.date}
109 onChange={date =>
110 setEventUpdate({
111 date: !date ? null : moment(date).format('YYYY-MM-DD'),
112 })
113 }
114 format="DD/MM/YYYY"
115 cancelLabel={t('generic.cancel')}
116 clearable
117 clearLabel={t('generic.clear')}
118 id={`${idPrefix}Date`}
119 />
120 ) : (
121 <Typography variant="body1" id={`${idPrefix}Date`}>
122 {event.date
123 ? moment(event.date).format('DD/MM/YYYY')
124 : t('event.fields.empty')}
125 </Typography>
126 )}
127 </div>
128 <div className={classes.section}>
129 <Typography variant="h6">{t('event.fields.address')}</Typography>
130 {isEditing ? (
131 <TextField
132 fullWidth
133 multiline
134 rowsMax={4}
135 inputProps={{maxLength: 250}}
136 helperText={`${event.address?.length ?? 0}/250`}
137 defaultValue={event.address}
138 value={event.address}
139 onChange={e => setEventUpdate({address: e.target.value})}
140 id={`${idPrefix}Address`}
141 name="address"
142 />
143 ) : (
144 <Typography variant="body1" id={`${idPrefix}Address`}>
145 {event.address ? (
146 <Link
147 target="_blank"
148 rel="noreferrer"
149 href={`https://www.google.com/maps/search/?api=1&query=${encodeURIComponent(
150 event.address
151 )}`}
152 onClick={e => e.preventDefault}
153 >
154 {event.address}
155 </Link>
156 ) : (
157 t('event.fields.empty')
158 )}
159 </Typography>
160 )}
161 </div>
162 <div className={classes.section}>
163 <Typography variant="h6">
164 {t('event.fields.description')}
165 </Typography>
166 {isEditing ? (
167 <TextField
168 fullWidth
169 multiline
170 rowsMax={4}
171 inputProps={{maxLength: 250}}
172 helperText={`${event.description?.length || 0}/250`}
173 defaultValue={event.description}
174 value={event.description || ''}
175 onChange={e => setEventUpdate({description: e.target.value})}
176 id={`${idPrefix}Description`}
177 name="description"
178 />
179 ) : (
180 <Typography variant="body1" id={`${idPrefix}Description`}>
181 {event.description ?? t('event.fields.empty')}
182 </Typography>
183 )}
184 </div>
185 <Typography variant="h6">{t('event.fields.link')}</Typography>
186 <Typography>{t('event.fields.link_desc')}</Typography>
187 <Box py={4} justifyContent="center" display="flex">
188 <ShareEvent
189 title={`Caroster ${event.name}`}
190 url={`${window.location.href}`}
191 />{' '}
192 </Box>
193 <Divider variant="middle" />
194 <Box pt={2} justifyContent="center" display="flex">
195 <Link href={settings?.about_link} target="_blank" rel="noopener">
196 {t('event.details.aboutCaroster')}
197 </Link>
198 </Box>
199 </Paper>
200 </Container>
201 </Box>
202 );
203};
204
205const useStyles = makeStyles(theme => ({
206 root: {
207 position: 'relative',
208 paddingLeft: '80px',
209
210 [theme.breakpoints.down('sm')]: {
211 paddingLeft: 0,
212 paddingBottom: '80px',
213 },
214 },
215 paper: {
216 position: 'relative',
217 padding: theme.spacing(2),
218 },
219 card: {
220 marginTop: theme.spacing(6),
221 },
222 modify: {
223 position: 'absolute',
224 right: theme.spacing(2),
225 },
226 section: {
227 marginBottom: theme.spacing(2),
228 width: '540px',
229 maxWidth: '100%',
230 paddingX: theme.spacing(2),
231 },
232 map: {
233 marginTop: theme.spacing(4),
234 },
235 seeOnGMapButton: {
236 marginLeft: theme.spacing(2),
237 },
238}));
239
240export const getServerSideProps = pageUtils.getServerSideProps(
241 async (context, apolloClient) => {
242 const {uuid} = context.query;
243 const {host = ''} = context.req.headers;
244
245 // Fetch event
246 const {data} = await apolloClient.query({
247 query: EventByUuidDocument,
248 variables: {uuid},
249 });
250 const event = data?.eventByUUID?.data;
251
252 return {
253 eventUUID: uuid,
254 metas: {
255 title: event?.attributes?.name || '',
256 url: `https://${host}${context.resolvedUrl}`,
257 },
258 };
259 }
260);
261export default Page;